package cn.anosi.shiro;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;

import cn.anosi.entity.auth.ActiveUser;
import cn.anosi.entity.auth.Permission;
import cn.anosi.entity.auth.User;
import cn.anosi.service.auth.UserService;

public class CustomRealm extends AuthorizingRealm {

	@Autowired
	UserService userService;

	// 设置realm的名称
	@Override
	public void setName(String name) {
		super.setName("customRealm");
	}

	// 认证
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		// 第一步从token中取出用户名
		String username = (String) token.getPrincipal();

		if(StringUtils.isBlank(username)){
			return null;
		}
		
		// 第二步：根据用户输入的username从数据库查询
		User user = userService.findByUsername(username);
		
		if (user == null) {
			// 如果查询不到返回null
			return null;
		}else{
			//根据用户id查询角色名
			List<String> names = userService.findUserRoleNames(user.getId());
			String roleNames = StringUtils.join(names.toArray(), ",");
			
			// 从数据库查询到密码
			String password = user.getPassword();
			// 盐
			String salt = user.getSalt();

			// activeUser就是用户身份信息
			ActiveUser activeUser = new ActiveUser();
			activeUser.setUserId(user.getId());
			activeUser.setRealname(user.getRealname());
			activeUser.setUsername(user.getUsername());
			activeUser.setRoleNames(roleNames);

			// 根据用户id取出菜单
			List<Permission> menus = userService.menus(user.getId());

			// 将用户菜单 设置到activeUser
			activeUser.setMenus(menus);

			/*
			 * 交给 AuthenticatingRealm 使用 CredentialsMatcher 进行密码匹配，如果觉得人家
			 * 的不好可以在此判断或自定义实现
			 */
			SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(activeUser, password,
					ByteSource.Util.bytes(salt), this.getName());

			return simpleAuthenticationInfo;
		}
	}

	// 授权
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		// 从 principals获取主身份信息
		// 将getPrimaryPrincipal方法返回值转为真实身份类型（在上边的doGetAuthenticationInfo认证通过填充到SimpleAuthenticationInfo中身份类型），
		ActiveUser activeUser = (ActiveUser) principals.getPrimaryPrincipal();

		// 根据身份信息获取权限信息
		// 从数据库获取到权限数据
		List<Permission> permissionList = null;
		try {
			permissionList = userService.permissions(activeUser.getUserId());
		} catch (Exception e) {
			e.printStackTrace();
		}
		// 单独定一个集合对象
		List<String> permissions = new ArrayList<String>();
		if (permissionList != null) {
			for (Permission p : permissionList) {
				// 将数据库中的权限标签 符放入集合
				permissions.add(p.getPercode());
			}
		}
		
		List<String> roleNames = userService.findUserRoleNames(activeUser.getUserId());

		// 查到权限数据，返回授权信息(要包括 上边的permissions)
		SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
		
		// 将上边查询到授权信息填充到simpleAuthorizationInfo对象中
		simpleAuthorizationInfo.addStringPermissions(permissions);
		simpleAuthorizationInfo.addRoles(roleNames);

		return simpleAuthorizationInfo;
	}

	// 清除缓存
	public void clearCached() {
		PrincipalCollection principals = SecurityUtils.getSubject().getPrincipals();
		super.clearCache(principals);
	}

}
